package http

import (
	"fmt"
	"net/http"
	"path"
	"reflect"
	"strconv"
	"strings"
	session2 "xrt/components/http/session"
	"xrt/components/http/session/sess"
	c "xrt/constants"
	. "xrt/core"
	"xrt/interfaces"
	"xrt/utils"
	"xrt/utils/file/log"
	"xrt/utils/maps"
	reflect2 "xrt/utils/reflect"
)

type xHttpLayer struct {
	host           string
	port           string
	cross          bool
	httpsOn        bool
	httpsPort      string
	httpsServerCrt string
	httpsServerKey string
	jwtOn          bool
	swaggerOn      bool
	patternMap     map[string]map[string]func(*XHttp)
	sessionManager *session.Manager
	async          interfaces.IfAsync
	templatePath   string
	staticPath     []string
	staticHead     string
	staticMD5      bool
}

type xHttpFilter struct {
}

func (h *xHttpLayer) Initial(configs map[string]string, syncMaps map[string]interface{}) {
	//初始化
	h.host = configs["http_host"]
	h.port = configs["http_port"]
	h.cross, _ = strconv.ParseBool(configs["allow_cors"])
	h.httpsOn, _ = strconv.ParseBool(configs["https_on"])
	h.httpsPort = configs["https_port"]
	h.httpsServerCrt = configs["https_server_crt"]
	h.httpsServerKey = configs["https_server_key"]
	h.jwtOn, _ = strconv.ParseBool(configs["jwt_on"])
	h.swaggerOn, _ = strconv.ParseBool(configs["swagger_on"])
	h.templatePath = maps.GetKeyWithDefaultS(configs, "template_path", "")
	h.staticHead = maps.GetKeyWithDefaultS(configs, "static_head", "")
	//h.staticMD5 = utils.ParseBool(configs["static_md5"])
	//静态文件目录注册
	for _, sPath := range strings.Split(configs["static_path"], ",") {
		//以相对路径开头需要处理一下路径
		if strings.HasPrefix(sPath, ".") {
			sPath = path.Join(c.RootPath, sPath)
		}
		h.staticPath = append(h.staticPath, sPath)
	}

	//是否启用Session
	if sessionOn, _ := strconv.ParseBool(configs["session_enable"]); sessionOn {
		h.sessionManager = session2.InitSession(configs)
	}

	//是否注入异步对象
	if asyncOn, _ := strconv.ParseBool(configs["async_on"]); asyncOn && X.GetAsyncInstants() != nil {
		h.async = X.GetAsyncInstants()
	}

	//生成Mux路由
	h.patternMap = map[string]map[string]func(*XHttp){}
	for pattern, handler := range syncMaps {
		//将default文件设置为包默认路径
		pattern = strings.Replace(pattern, "/default/", "/", -1)
		//设置所有命名为Default的RouteSync为默认访问路径
		if strings.HasSuffix(pattern, "Default") {
			pattern = pattern[0 : len(pattern)-7]
		}
		//过滤掉xHttp保留内容
		if !utils.InArray(XHttpInnerPath, pattern) {
			log.Debugf("Generate Sync Route Pattern: %s", pattern)
		}

		muxTyp := reflect.TypeOf(handler)
		muxVal := reflect.ValueOf(handler)
		//判定是否存在特殊匹配
		extMatch := muxVal.MethodByName("ExtMatch")
		if extMatch.IsValid() {
			pattern += extMatch.Call(nil)[0].Interface().(string)
		}

		h.patternMap[pattern] = map[string]func(*XHttp){}
		for i := 0; i < muxTyp.NumMethod(); i++ {
			muxTypMethod := muxTyp.Method(i)
			muxValMethod := muxVal.Method(i)
			if muxTypMethod.Name == "ExtMatch" {
				continue
			}
			h.patternMap[pattern][muxTypMethod.Name] = muxValMethod.Interface().(func(*XHttp))
		}
	}
	//注册静态文件
	if h.staticHead != "" {
		staticMatch := h.staticHead + "/(.*)"
		h.patternMap[staticMatch] = map[string]func(*XHttp){}
		h.patternMap[staticMatch]["Get"] = DisposeStaticResource
	}
}

func (h *xHttpLayer) Listening() {
	log.Infof(fmt.Sprintf("Start HTTP Comsuming [%s:%s] ...", h.host, h.port))
	log.Critical(http.ListenAndServe(fmt.Sprintf("%s:%s", h.host, h.port), h))
}

func checkFilter(se interface{}) (string, string) {
	sType := reflect.TypeOf(se)
	fileName := strings.Split(reflect2.GetFileName(3), ".")[0]
	sName := sType.Name()
	if strings.HasSuffix(fileName, "_filters") {
		fileName = string(fileName[0 : len(fileName)-8])
	} else {
		panic("Filter File must be endsWith [_filters].")
	}
	if strings.HasSuffix(sName, "Filter") {
		sName = string(sName[0 : len(sName)-6])
	} else {
		panic("Filter Structure must be endsWith [Filter].")
	}
	routePath := fmt.Sprintf("%s/%s", sType.PkgPath(), fileName)
	//如果是Default命名则不注册Structure名
	if sName != "Default" {
		routePath += fmt.Sprintf("/%s", sName)
	}
	routePath = strings.SplitN(routePath, c.AppHead, 2)[1]
	filterPath := fmt.Sprintf("%s/%s/%s", sType.PkgPath(), fileName+"_filters", sName+"Filter")
	filterPath = strings.SplitN(filterPath, c.AppHead, 2)[1]
	return routePath, filterPath
}

//注册Filter
func RegisterFilter(fi interface{}) {
	routePath, filterPath := checkFilter(fi)
	if _, ok := filtersMap[routePath]; ok {
		//filtersMap[routePath] = append(filtersMap[routePath], fi.(func(*XHttp)))
		fmt.Printf("Register Filter \t[%s] For [%s]\n", filterPath, routePath)
	}
}

var filtersMap map[string]map[string][]func(*XHttp)

func init() {
	//实例化过滤器列表
	filtersMap = map[string]map[string][]func(*XHttp){}
	X.RegisterComponent(c.ImplSync, xHttpLayer{})
}
